////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 1999-2010.
// -------------------------------------------------------------------------
//  File name:	DeepSelection.h
//  Version:	v1.00
//  Created:	2008/08/19 by Paulo Zaffari
//  Description: 	This file declares a control which objective is to display 
//								multiple Assets allowing selection and preview of such things.
//								It also must handle scrolling and changes in the Asset 
//								cell display size.
// -------------------------------------------------------------------------  
//  History:
//		- 19/08/2008   12:54 : Created by Paulo Zaffari
//		- 11/03/2010   17:34 : Nicusor Nedelcu - refactored
//
//////////////////////////////////////////////////////////////////////////// 

#ifndef __AssetViewer_h__
#define __AssetViewer_h__
#pragma once

#include "ScrollableWindow.h"
#include "CryThread.h"
#include "MultiThread_Containers.h"
#include "Include/IAssetViewer.h"
#include "Include/IAssetDisplayDatabase.h"
#include "Util/GdiUtil.h"
#include "Include/Observable.h"
#include "Asset Browser/AssetBrowserCommon.h"

// Description:
//		This class is the main control to display and browser assets by their thumbnail images, also it has tag editing and other functionalities
class CAssetViewer : public CScrollableWindow, public IAssetViewer, public CObservable<IAssetViewerObserver>, public CryThread<CAssetViewer>, public IEditorNotifyListener
{
	public:

		// needed only because we are inheriting from a pure interface
		IMPLEMENT_OBSERVABLE_METHODS(IAssetViewerObserver);

		// Description:
		//		This struct is used to hold info about mini buttons found on the thumbnail side
		struct CThumbMiniButton
		{
			// callback type used when a thumbnail mini button is clicked
			typedef void (*TClickCallback)( IAssetDisplay* pAsset );

			CThumbMiniButton()
			{
				m_pfnOnClick = NULL;
			}

			CThumbMiniButton( TClickCallback	pfnOnClick, const char* pToolTipText, const char* pImageFilename )
			{
				m_pfnOnClick = pfnOnClick;
				m_toolTip = pToolTipText;
				m_image.Load( pImageFilename, true );
			}

			TClickCallback	m_pfnOnClick;
			CString					m_toolTip;
			CAlphaBitmap		m_image;
		};

		// Description:
		//		This struct is used to hold info about mini buttons found on the thumbnail side
		struct CThumbMiniButtonInstance
		{
			CThumbMiniButtonInstance()
			{
				m_pMiniButton = NULL;
				m_pAsset = NULL;
				m_bOn = false;
			}

			CThumbMiniButtonInstance( CThumbMiniButton* pMiniButton, const CRect& rRect, IAssetDisplay* pAsset, bool bOn )
			{
				m_pMiniButton = pMiniButton;
				m_rect = rRect;
				m_pAsset = pAsset;
				m_bOn = bOn;
			}

			CThumbMiniButton*		m_pMiniButton;
			CRect								m_rect;
			IAssetDisplay*			m_pAsset;
			bool								m_bOn;
		};

		// For each visible asset, we will have a vector of thumb button instances
		typedef std::map<IAssetDisplay*,std::vector<CThumbMiniButtonInstance>> TThumbMiniButtonInstances;

		CAssetViewer();
		~CAssetViewer();
		void	FreeData();
		bool	Create( int nLeft, int nTop, UINT nWidth, UINT nHeight, CWnd* poParentWindow, UINT nId = -1, DWORD dwStyle = WS_CHILD | WS_VISIBLE );

		void	Run();
		void	RestartThread();
		void	WaitThreadAndFreeData();

		void	LockAll();
		void	UnlockAll();
		void	LockAssetItemsArray();
		void	UnlockAssetItemsArray();
		void	LockAssetDatabasesArray();
		void	UnlockAssetDatabasesArray();
		void	SetDatabases( TAssetDatabases& rcDatabases );
		TAssetDatabases& GetDatabases();
		void	RefreshDatabases();
		void	RefreshAssetsUsedInLevel();
		void	ClearDatabases();
		void	SortAssets( const char* pFieldname, bool bDescending = false );
		void	ApplyFilters( const IAssetDisplayDatabase::TAssetFieldFiltersMap& rFieldFilters );
		void	ClearFilters();
		void	EnsureAssetVisible( UINT aIndex, bool bPlayFocusAnimation = false );
		void	EnsureAssetVisible( IAssetDisplay* pAsset, bool bPlayFocusAnimation = false );
		void	SetAssetThumbSize( const unsigned int nThumbSize );
		UINT	GetAssetThumbSize();
		void	GetSelectedItems( TAssetItems& rSelectedItems );
		int		GetFirstSelectedItemIndex();
		void	SelectAsset( IAssetDisplay* pAsset );
		void	SelectAssets( const TAssetItems& rSelectedItems );
		void	DeselectAll( bool bCallObservers = true );
		HWND	GetRenderWindow();
		void	PushToThumbsCacheQueue( IAssetDisplay* pAsset );
		TAssetItems& GetAssetItems();
		bool	IsAssetVisibleInView( IAssetDisplay* pAsset );
		// Return Value:
		//		True if the user is holding the mouse left button down and drags the pointer inside a thumb, interacting with the asset object
		//		used when some asset needs the viewport to cache its object (models need the viewport to render in)
		bool	IsThumbViewportInteraction();
		void	UpdateSmoothPanning();
		void	CachePendingNonThreadedAssets();
		static CString GetAssetFieldDisplayValue( IAssetDisplay* pAsset, const char* pFieldname );
		void	RecalculateTotalAssetCount();
		void	CachingStarted();
		void	CachingEnded();
		void	SetCachingProgress( int aCachingCurrentCount = 0, int aCachingTotalCount = 0 );
		bool	IsCachingInProgress();
		bool	IsCachingCancelled();
		// from IEditorNotifyListener
		// Here we receive the idle updates, from which we call the rendering method
		void OnEditorNotifyEvent( EEditorNotifyEvent event );

	protected:

		DECLARE_MESSAGE_MAP()
		afx_msg void OnSize(UINT nType,int cx,int cy);
		afx_msg void OnPaint();
		afx_msg BOOL OnEraseBkgnd(CDC* pDC);
		afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
		afx_msg void OnMouseMove(UINT nFlags,CPoint point);
		afx_msg void OnLButtonUp(UINT nFlags,CPoint point);
		afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
		afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
		afx_msg BOOL OnMouseWheel(UINT nFlags,short zDelta,CPoint pt);
		afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
		afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
		afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
		afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
		afx_msg void OnTimer(UINT_PTR nIDEvent);
		afx_msg void OnDestroy();
		afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
		afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
		afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);

		// Description:
		//		Calculates the layout of all visible assets
		void RecalculateLayout();
		// Description:
		//		Calculates the currently visible elements.
		void UpdateVisibility();
		// Description:
		//		Update scroll bar range and vertical offset
		void UpdateScrollBar();
		// Description:
		//		Draw all ( asset thumbs, tooltip, etc. )
		void Draw();
		// Description:
		//		Draw a single asset
		// Arguments:
		//		poItem - the item do be drawn
		//		roDrawRect - where to draw the item
		void DrawAsset( IAssetDisplay* poItem, CRect& roDrawRect );
		void DrawThumbTooltip( CDC& dc );
		void DrawThumbMiniButtonTooltip( CDC& dc );
		void DrawFocusThumbAnimationRect( CDC& dc );
		void DrawCachingInfoProgressBar( CDC& dc );
		void DrawThumbnail( CDC& dc, IAssetDisplay* const poItem, const CRect& roUpdateRect );
		void DrawThumbMiniButtons( IAssetDisplay* const poItem, const CRect& rcThumbBorder );
		// Description:
		//		Add an asset to the timer caching queue, if it cannot be cached on the thread
		// Arguments:
		//		poItem - the item do be added to the timer caching queue
		void EnqueueAssetForCaching( IAssetDisplay* poItem );
		// Description:
		//		Check for a virtual key press
		bool CheckVirtualKey( int virtualKey );
		// Description:
		//		Check for the currently clicked thumbnail, will set the m_poClickedAsset member
		// Arguments:
		//		nFlags - keyboard/mouse flags, see WM_LBUTTONDOWN for example
		//		point - the current mouse position, relative to the control
		//		bShowInteractiveRenderWnd - if true, the small thumb window will be placed and shown on the thumb spot if some asset is clicked
		void CheckClickedThumb( UINT nFlags, CPoint point, bool bShowInteractiveRenderWnd = false );
		void CheckHoveredThumb();
		// Description:
		//		Function used by the sorting mechanism
		// Arguments:
		//		pA - first item to compare
		//		pB - second item to compare
		// Return Value:
		//		true if pA must be before pB
		static bool SortAssetItems( IAssetDisplay* pA, IAssetDisplay* pB );
		static bool SortAssetsByIndex( IAssetDisplay* pA, IAssetDisplay* pB );
		static void OnThumbButtonClickTags( IAssetDisplay* pAsset );
		static void OnThumbButtonClickFavourite( IAssetDisplay* pAsset );

		// Description:
		//		Used for shortening the code in the switch-case construct, in CAssetViewer::SortAssetItems
		template<class T>
		static inline bool CompareAssetFieldsValues( IAssetDisplay* pA, IAssetDisplay* pB )
		{
			T valueA, valueB;

			if( !pA->GetAssetFieldValue( s_pSortField->m_fieldName, &valueA ) ||
					!pB->GetAssetFieldValue( s_pSortField->m_fieldName, &valueB ) )
				return false;

			return s_bSortDescending ? valueA > valueB : valueA < valueB;
		}

		// current asset field used in sorting of the assets
		static SAssetField*					s_pSortField;
		// used for the sorting function
		static bool									s_bSortDescending;
		// mutex used to protect a multiple lock chain from deadlock
		static CryMutex							s_lockAll;
		// reference count of the class
		ULONG												m_ref;
		// the current asset items rendered in this viewer
		TAssetItems									m_cAssetItems;
		// the current visible/drawing asset thumbs in the control
		TAssetItems									m_cAssetDrawingCache;
		// this is the list of assets which are waiting to be cached, and cannot be cached on the caching thread
		TAssetItems									m_cPendingCacheAssets;
		// the list of currently selected assets
		TAssetItems									m_cSelectedAssets;
		// the databases currently visible and used in the control
		TAssetDatabases							m_cAssetDatabases;
		// mutex for when the m_cAssetItems is used between threads
		CryMutex										m_oAssetItemsLock, 
		// mutex for when the m_cAssetDatabases is used between threads
																m_oAssetDatabasesLock;
		// the total number of assets from all databases and all non filtered items
		UINT												m_nTotalAssets;
		// the thumbs cache used to hold track of the generated thumbs, it can have a certain size, afterwards it starts discarding older items
		std::deque<IAssetDisplay*>	m_cThumbsCache;
		// the fieldname currently used for sorting the asset list view
		CString											m_strCurrentSortFieldname;
		// point used for dragging a rectangle to select items
		CPoint											m_oStartDraggingPoint;
		// true if mouse left button is down
		bool												m_bMouseLeftButtonDown;
		// true if mouse right button is down
		bool												m_bMouseRightButtonDown;
		// true if mouse middle/wheel button is down
		bool												m_bMouseMiddleButtonDown;
		// true if dragging of a selection rectangle is in process
		bool												m_bDragging;
		// the current selection rectangle
		CRect												m_oSelectionRect;
		// horizontal spacing between thumbs
		UINT												m_nItemHorizontalSpacing;
		// vertical spacing between thumbs
		UINT												m_nItemVerticalSpacing;
		// the asset thumb size (width and height are always equal)
		UINT												m_nAssetThumbSize;
		// the current offset of the thumbs canvas, depends on the scrolling position and the vertical scrollbar
		int													m_nYOffset;
		// the amount used to pan vertically the thumbs canvas; the remaining amount which is decreased by a timer to have a smooth animated pan effect
		float												m_smoothPanLeftAmount;
		// the last delta value between two dragging mouse actions, used in smooth panning
		int													m_smoothPanLastDelta;
		// the client rectangle changes only on control resize
		CRect												m_oClientRect;
		// the width of the virtual canvas on which thumbs are drawn, used for computing scrollbar ranges
		UINT												m_nIdealClientWidth;
		// the height of the virtual canvas on which thumbs are drawn, used for computing scrollbar ranges
		UINT												m_nIdealClientHeight;
		// if not NULL, this asset item will be always kept into the view
		IAssetDisplay								*m_poEnsureVisible;
		// the currently clicked asset item
		IAssetDisplay								*m_poClickedAsset;
		// the currently hovered asset item
		IAssetDisplay								*m_poHoveredAsset;
		// the pointer to the current engine renderer
		IRenderer										*m_piRenderer;
		// the (child) window used to render thumbnails, and sometimes if the asset type supports it, the user can interact with the asset in this window
		// placed at the selected thumb position
		CWnd												m_wndAssetThumbRender;
		// the GDI canvas object used to render the thumbs in a memory image (DC) buffer
		CGdiCanvas									m_canvas;
		// bitmap used for thumb shadow and tooltip body
		CAlphaBitmap								m_thumbShadowBmp,
		// bitmap used for the asset thumb loading state
																m_thumbLoadingBmp,
		// bitmap used for the control's background
																m_backgroundBmp,
		// bitmap used for the invalid asset thumb state
																m_thumbInvalidAssetBmp;
		// the browser's draw back brush
		CBrush											m_backBrush;
		// font for the thumb labels
		CFont												m_fontLabel,
		// font for the info text found in the tooltip over asset thumbs
																m_fontInfoText,
		// font for the tooltip info title (asset filename)
																m_fontInfoTitle,
		// font for the text below the thumb label, used for additional asset-type-specific info, on one single line
																m_fontOneLinerInfo;
		// used for drag panning of the thumbs canvas, relative to control
		CPoint											m_lastPanDragPt,
		// used to remember the last right mouse click location, relative to control
																m_lastRightClickPt;
		// will be set to true by the caching thread when the control must be redrawn
		volatile bool								m_bMustRedraw;
		// true when the user is currently dragging asset from browser to viewports
		bool												m_bDraggingAssetFromBrowser,
		// true when the asset was dragged and mouse button released, the user is now moving the created asset in the world
		// a second click will set the translation and end creation process, and ESCAPE will abort creation
																m_bDraggingCreatedAssetInWorld;
		// the dragged and created asset instance, depends on the asset, usually a CBaseObject
		void*												m_pDraggedAssetInstance;
		// the viewport on which the user has dropped the dragged asset
		CViewport*									m_pDropInViewport;
		// the actual viewport dragged asset
		IAssetDisplay*							m_pDraggedAsset;
		// used for smooth pannning with right mouse button drag, timing, last tick count (GetTickCount)
		UINT												m_smoothPanningLastTickCount;
		// true when a red rectangle is preset and must be drawn on assets which have the eAssetFlag_HasErrors flag on
		bool												m_bWarningBlinkToggler;
		// when the user select an asset in the list view, the browser will animate a focus rect towards the selected asset thumb
		// this is the animated rectangle
		CRect												m_thumbFocusAnimationRect;
		// used in animating the focusing rect for the selected asset thumb, between 0..1, 1 is completed animation
		float												m_thumbFocusAnimationTime;
		// asset thumbs per one row
		UINT												m_nThumbsPerRow,
		// the current visible asset thumb row count
																m_nVisibleThumbRows;
		// thumb mini buttons templates, found on the side of each asset thumb, for example: Edit tags, Toggle favourite
		std::vector<CThumbMiniButton*>	m_thumbMiniButtons;
		// the instances with position and state, of the thumb mini buttons for all the visible in-view asset thumbs
		TThumbMiniButtonInstances		m_thumbMiniButtonInstances;
		// the currently asset which has a mini thumb button hovered
		IAssetDisplay*							m_pHoveredThumbButtonAsset;
		// the currently hovered mini thumb button index (in the m_thumbMiniButtons vector)
		UINT												m_nHoveredThumbButtonIndex;
		// a small dotted icon shown on the label of each draggable asset, signalling that the asset can be dragged into viewports
		HICON												m_hDraggableAssetIcon, 
		// small warning icon used on the caching progress bar
																m_hWarningSmallIcon;
		// the current caching info count, used for the progress bar
		int													m_cachingCurrentCount,
		// the current caching info total count, used for the progress bar
																m_cachingTotalCount;
		// true if caching of asset info is in progress
		bool												m_bCachingInProgress, 
		// true if the cancel caching info button is hovered
																m_bCancelCachingButtonHovered,
		// true if the cancel caching info button was pressed/clicked
																m_bCancelCachingButtonPressed;
		// the rectangle used to draw the cance info button
		CRect												m_cancelCachingButtonRect;
		// the current used assets in the loaded level
		std::set<CString>						m_usedAssetsInLevel;
		 
};

#endif //__AssetViewer_h__
